using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.Diagnostics.CodeAnalysis;
using Xunit;

namespace ModelContextProtocol.Analyzers.Tests;

public partial class XmlToDescriptionGeneratorTests
{
    [Fact]
    public void Generator_WithSummaryOnly_GeneratesMethodDescription()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool description
                /// </summary>
                [McpServerTool]
                public static partial string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool description")]
                    public static partial string TestMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithSummaryAndRemarks_CombinesInMethodDescription()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool summary
                /// </summary>
                /// <remarks>
                /// Additional remarks
                /// </remarks>
                [McpServerTool]
                public static partial string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool summary\nAdditional remarks")]
                    public static partial string TestMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithParameterDocs_GeneratesParameterDescriptions()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool
                /// </summary>
                /// <param name="input">Input parameter description</param>
                /// <param name="count">Count parameter description</param>
                [McpServerTool]
                public static partial string TestMethod(string input, int count)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool")]
                    public static partial string TestMethod([Description("Input parameter description")] string input, [Description("Count parameter description")] int count);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithReturnDocs_GeneratesReturnDescription()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool
                /// </summary>
                /// <returns>The result of the operation</returns>
                [McpServerTool]
                public static partial string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool")]
                    [return: Description("The result of the operation")]
                    public static partial string TestMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithExistingMethodDescription_DoesNotGenerateMethodDescription()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool summary
                /// </summary>
                /// <returns>Result</returns>
                [McpServerTool]
                [Description("Already has description")]
                public static partial string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [return: Description("Result")]
                    public static partial string TestMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithExistingParameterDescription_SkipsThatParameter()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool
                /// </summary>
                /// <param name="input">Input description</param>
                /// <param name="count">Count description</param>
                [McpServerTool]
                public static partial string TestMethod(string input, [Description("Already has")] int count)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool")]
                    public static partial string TestMethod([Description("Input description")] string input, int count);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithoutMcpServerToolAttribute_DoesNotGenerate()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            public partial class TestTools
            {
                /// <summary>
                /// Test tool
                /// </summary>
                public static partial string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
    }

    [Fact]
    public void Generator_WithoutPartialKeyword_DoesNotGenerate()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <summary>
                /// Test tool
                /// </summary>
                [McpServerTool]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
    }

    [Fact]
    public void Generator_NonPartialMethodWithXmlDocs_ReportsMCP002Diagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <summary>
                /// Test tool with documentation
                /// </summary>
                [McpServerTool]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should report MCP002 diagnostic
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
        Assert.Contains("TestMethod", diagnostic.GetMessage());
        Assert.Contains("partial", diagnostic.GetMessage());
    }

    [Fact]
    public void Generator_NonPartialMethodWithParameterDocs_ReportsMCP002Diagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <param name="input">Input parameter</param>
                [McpServerTool]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should report MCP002 diagnostic because parameter has documentation
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
    }

    [Fact]
    public void Generator_NonPartialMethodWithReturnDocs_ReportsMCP002Diagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <returns>Return value</returns>
                [McpServerTool]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should report MCP002 diagnostic because return has documentation
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
    }

    [Fact]
    public void Generator_NonPartialMethodWithoutXmlDocs_DoesNotReportDiagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                [McpServerTool]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should NOT report MCP002 diagnostic because there's no XML documentation
        Assert.DoesNotContain(result.Diagnostics, d => d.Id == "MCP002");
    }

    [Fact]
    public void Generator_NonPartialMethodWithEmptyXmlDocs_DoesNotReportDiagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <summary></summary>
                [McpServerTool]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should NOT report MCP002 diagnostic because XML documentation is empty
        Assert.DoesNotContain(result.Diagnostics, d => d.Id == "MCP002");
    }

    [Fact]
    public void Generator_NonPartialMethodWithExistingDescriptions_DoesNotReportDiagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <summary>Test tool</summary>
                /// <param name="input">Input param</param>
                /// <returns>Return value</returns>
                [McpServerTool]
                [Description("Already has method description")]
                [return: Description("Already has return description")]
                public static string TestMethod([Description("Already has param description")] string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should NOT report MCP002 diagnostic because all descriptions already exist
        Assert.DoesNotContain(result.Diagnostics, d => d.Id == "MCP002");
    }

    [Fact]
    public void Generator_NonPartialMethodWithPartialExistingDescriptions_ReportsMCP002Diagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public class TestTools
            {
                /// <summary>Test tool</summary>
                /// <param name="input">Input param</param>
                [McpServerTool]
                [Description("Already has method description")]
                public static string TestMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should report MCP002 diagnostic because parameter description would be generated
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
    }

    [Fact]
    public void Generator_NonPartialPromptWithXmlDocs_ReportsMCP002Diagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerPromptType]
            public class TestPrompts
            {
                /// <summary>
                /// Test prompt
                /// </summary>
                [McpServerPrompt]
                public static string TestPrompt(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should report MCP002 diagnostic for prompts too
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
    }

    [Fact]
    public void Generator_NonPartialResourceWithXmlDocs_ReportsMCP002Diagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerResourceType]
            public class TestResources
            {
                /// <summary>
                /// Test resource
                /// </summary>
                [McpServerResource("test://resource")]
                public static string TestResource(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Empty(result.GeneratedSources);
        
        // Should report MCP002 diagnostic for resources too
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP002");
        Assert.Equal(DiagnosticSeverity.Info, diagnostic.Severity);
    }

    [Fact]
    public void Generator_WithSpecialCharacters_EscapesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test with "quotes", \backslash, newline
                /// and tab characters.
                /// </summary>
                /// <param name="input">Parameter with "quotes"</param>
                [McpServerTool]
                public static partial string TestEscaping(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test with \"quotes\", \\backslash, newline and tab characters.")]
                    public static partial string TestEscaping([Description("Parameter with \"quotes\"")] string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithInvalidXml_GeneratesPartialAndReportsDiagnostic()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test with <unclosed tag
                /// </summary>
                [McpServerTool]
                public static partial string TestInvalidXml(string input)
                {
                    return input;
                }
            }
            """);

        // Should not throw, generates partial implementation without Description attributes
        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    public static partial string TestInvalidXml(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
        
        // Should report a warning diagnostic
        var diagnostic = Assert.Single(result.Diagnostics, d => d.Id == "MCP001");
        Assert.Equal(DiagnosticSeverity.Warning, diagnostic.Severity);
        Assert.Contains("invalid", diagnostic.GetMessage(), StringComparison.OrdinalIgnoreCase);
    }

    [Fact]
    public void Generator_WithGenericType_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools<T>
            {
                /// <summary>
                /// Test generic
                /// </summary>
                [McpServerTool]
                public static partial string TestGeneric(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test generic")]
                    public static partial string TestGeneric(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithEmptyXmlComments_GeneratesPartialWithoutDescription()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// </summary>
                [McpServerTool]
                public static partial string TestEmpty(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    public static partial string TestEmpty(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithMultilineComments_CombinesIntoSingleLine()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// First line
                /// Second line
                /// Third line
                /// </summary>
                [McpServerTool]
                public static partial string TestMultiline(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("First line Second line Third line")]
                    public static partial string TestMultiline(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithParametersOnly_GeneratesParameterDescriptions()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <param name="input">Input parameter</param>
                /// <param name="count">Count parameter</param>
                [McpServerTool]
                public static partial string TestMethod(string input, int count)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    public static partial string TestMethod([Description("Input parameter")] string input, [Description("Count parameter")] int count);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithNestedType_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            public partial class OuterClass
            {
                [McpServerToolType]
                public partial class InnerClass
                {
                    /// <summary>
                    /// Nested tool
                    /// </summary>
                    [McpServerTool]
                    public static partial string NestedMethod(string input)
                    {
                        return input;
                    }
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class OuterClass
                {
                    partial class InnerClass
                    {
                        [Description("Nested tool")]
                        public static partial string NestedMethod(string input);
                    }
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithManyToolsAcrossMultipleNestedTypes_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test.Outer;

            [McpServerToolType]
            public partial class RootTools
            {
                /// <summary>Root level tool 1</summary>
                [McpServerTool]
                public static partial string RootTool1(string input) => input;

                /// <summary>Root level tool 2</summary>
                /// <param name="count">The count</param>
                [McpServerTool]
                public static partial string RootTool2(string input, int count) => input;
            }

            public partial class OuterContainer
            {
                [McpServerToolType]
                public partial class Level2A
                {
                    /// <summary>Level 2A tool</summary>
                    [McpServerTool]
                    public static partial string Level2ATool(string input) => input;

                    public partial class Level3
                    {
                        [McpServerToolType]
                        public partial class Level4
                        {
                            /// <summary>Deep nested tool</summary>
                            /// <returns>The result</returns>
                            [McpServerTool]
                            public static partial string DeepTool(string input) => input;
                        }
                    }
                }

                [McpServerToolType]
                public partial class Level2B
                {
                    /// <summary>Level 2B tool 1</summary>
                    [McpServerTool]
                    public static partial string Level2BTool1(string input) => input;

                    /// <summary>Level 2B tool 2</summary>
                    [McpServerTool]
                    public static partial string Level2BTool2(string input) => input;
                }
            }

            namespace Test.Resources;

            [McpServerResourceType]
            public partial class ResourceProviders
            {
                /// <summary>Test resource 1</summary>
                /// <param name="path">The path</param>
                [McpServerResource("test:///{path}")]
                public static partial string Resource1(string path) => path;

                /// <summary>Test resource 2</summary>
                [McpServerResource("test2:///{id}")]
                public static partial string Resource2(string id) => id;
            }

            [McpServerPromptType]
            public partial class GlobalPrompts
            {
                /// <summary>Global prompt</summary>
                [McpServerPrompt]
                public static partial string GlobalPrompt(string input) => input;
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test.Outer
            {
                partial class RootTools
                {
                    [Description("Root level tool 1")]
                    public static partial string RootTool1(string input);

                    [Description("Root level tool 2")]
                    public static partial string RootTool2(string input, [Description("The count")] int count);
                }

                partial class OuterContainer
                {
                    partial class Level2A
                    {
                        [Description("Level 2A tool")]
                        public static partial string Level2ATool(string input);
                    }
                }

                partial class OuterContainer
                {
                    partial class Level2A
                    {
                        partial class Level3
                        {
                            partial class Level4
                            {
                                [Description("Deep nested tool")]
                                [return: Description("The result")]
                                public static partial string DeepTool(string input);
                            }
                        }
                    }
                }

                partial class OuterContainer
                {
                    partial class Level2B
                    {
                        [Description("Level 2B tool 1")]
                        public static partial string Level2BTool1(string input);

                        [Description("Level 2B tool 2")]
                        public static partial string Level2BTool2(string input);
                    }
                }
            }
            
            namespace Test.Outer.Test.Resources
            {
                partial class GlobalPrompts
                {
                    [Description("Global prompt")]
                    public static partial string GlobalPrompt(string input);
                }

                partial class ResourceProviders
                {
                    [Description("Test resource 1")]
                    public static partial string Resource1([Description("The path")] string path);

                    [Description("Test resource 2")]
                    public static partial string Resource2(string id);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithRecordClass_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial record TestTools
            {
                /// <summary>
                /// Record tool
                /// </summary>
                [McpServerTool]
                public static partial string RecordMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial record class TestTools
                {
                    [Description("Record tool")]
                    public static partial string RecordMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithRecordStruct_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial record struct TestTools
            {
                /// <summary>
                /// Record struct tool
                /// </summary>
                [McpServerTool]
                public static partial string RecordStructMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial record struct TestTools
                {
                    [Description("Record struct tool")]
                    public static partial string RecordStructMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithVirtualMethod_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Virtual tool
                /// </summary>
                [McpServerTool]
                public virtual partial string VirtualMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Virtual tool")]
                    public virtual partial string VirtualMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithAbstractMethod_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public abstract partial class TestTools
            {
                /// <summary>
                /// Abstract tool
                /// </summary>
                [McpServerTool]
                public abstract partial string AbstractMethod(string input);
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Abstract tool")]
                    public abstract partial string AbstractMethod(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithMcpServerPrompt_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerPromptType]
            public partial class TestPrompts
            {
                /// <summary>
                /// Test prompt
                /// </summary>
                [McpServerPrompt]
                public static partial string TestPrompt(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestPrompts
                {
                    [Description("Test prompt")]
                    public static partial string TestPrompt(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithMcpServerResource_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerResourceType]
            public partial class TestResources
            {
                /// <summary>
                /// Test resource
                /// </summary>
                [McpServerResource("test://resource")]
                public static partial string TestResource(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);
        
        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestResources
                {
                    [Description("Test resource")]
                    public static partial string TestResource(string input);
                }
            }
            """;
        
        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithGlobalNamespace_GeneratesCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            [McpServerToolType]
            public partial class GlobalTools
            {
                /// <summary>
                /// Tool in global namespace
                /// </summary>
                [McpServerTool]
                public static partial string GlobalMethod(string input)
                {
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);

        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            partial class GlobalTools
            {
                [Description("Tool in global namespace")]
                public static partial string GlobalMethod(string input);
            }
            """;

        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithDefaultParameterValues_PreservesDefaults()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool with defaults
                /// </summary>
                /// <param name="project">The project name</param>
                /// <param name="flag">Enable flag</param>
                /// <param name="count">Item count</param>
                [McpServerTool]
                public static partial string TestMethod(
                    string? project = null,
                    bool flag = false,
                    int count = 42)
                {
                    return project ?? "default";
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);

        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool with defaults")]
                    public static partial string TestMethod([Description("The project name")] string? project = null, [Description("Enable flag")] bool flag = false, [Description("Item count")] int count = 42);
                }
            }
            """;

        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithAsyncMethod_ExcludesAsyncModifier()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;
            using System.Threading.Tasks;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Async tool
                /// </summary>
                [McpServerTool]
                public async partial Task<string> DoWorkAsync(string input)
                {
                    await Task.Delay(100);
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);

        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Async tool")]
                    public partial Task<string> DoWorkAsync(string input);
                }
            }
            """;

        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithAsyncStaticMethod_ExcludesAsyncModifier()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;
            using System.Threading.Tasks;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Static async tool
                /// </summary>
                [McpServerTool]
                public static async partial Task<string> StaticAsyncMethod(string input)
                {
                    await Task.Delay(100);
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);

        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Static async tool")]
                    public static partial Task<string> StaticAsyncMethod(string input);
                }
            }
            """;

        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithDefaultParameterValuesAndAsync_HandlesBothCorrectly()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;
            using System.Threading.Tasks;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Async tool with defaults
                /// </summary>
                /// <param name="input">The input</param>
                /// <param name="timeout">Timeout in ms</param>
                [McpServerTool]
                public static async partial Task<string> AsyncWithDefaults(string input, int timeout = 1000)
                {
                    await Task.Delay(timeout);
                    return input;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);

        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Async tool with defaults")]
                    public static partial Task<string> AsyncWithDefaults([Description("The input")] string input, [Description("Timeout in ms")] int timeout = 1000);
                }
            }
            """;

        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    [Fact]
    public void Generator_WithStringDefaultValue_PreservesQuotedDefault()
    {
        var result = RunGenerator("""
            using ModelContextProtocol.Server;
            using System.ComponentModel;

            namespace Test;

            [McpServerToolType]
            public partial class TestTools
            {
                /// <summary>
                /// Test tool with string default
                /// </summary>
                [McpServerTool]
                public static partial string TestMethod(string name = "default value")
                {
                    return name;
                }
            }
            """);

        Assert.True(result.Success);
        Assert.Single(result.GeneratedSources);

        var expected = $$"""
            // <auto-generated/>
            // ModelContextProtocol.Analyzers {{typeof(XmlToDescriptionGenerator).Assembly.GetName().Version}}

            #pragma warning disable

            using System.ComponentModel;
            using ModelContextProtocol.Server;

            namespace Test
            {
                partial class TestTools
                {
                    [Description("Test tool with string default")]
                    public static partial string TestMethod(string name = "default value");
                }
            }
            """;

        AssertGeneratedSourceEquals(expected, result.GeneratedSources[0].SourceText.ToString());
    }

    private GeneratorRunResult RunGenerator([StringSyntax("C#-test")] string source)
    {
        var syntaxTree = CSharpSyntaxTree.ParseText(source);

        // Get reference assemblies - we need to include all the basic runtime types
        List<MetadataReference> referenceList =
        [
            MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
            MetadataReference.CreateFromFile(typeof(System.ComponentModel.DescriptionAttribute).Assembly.Location),
        ];

        // Add all necessary runtime assemblies
        var runtimePath = Path.GetDirectoryName(typeof(object).Assembly.Location)!;
        referenceList.Add(MetadataReference.CreateFromFile(Path.Combine(runtimePath, "System.Runtime.dll")));
        referenceList.Add(MetadataReference.CreateFromFile(Path.Combine(runtimePath, "netstandard.dll")));

        // Try to find and add ModelContextProtocol.Core
        try
        {
            var coreAssemblyPath = Path.Combine(AppContext.BaseDirectory, "ModelContextProtocol.Core.dll");
            if (File.Exists(coreAssemblyPath))
            {
                referenceList.Add(MetadataReference.CreateFromFile(coreAssemblyPath));
            }
        }
        catch
        {
            // If we can't find it, the compilation will fail with appropriate errors
        }

        var compilation = CSharpCompilation.Create(
            "TestAssembly",
            [syntaxTree],
            referenceList,
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

        var driver = (CSharpGeneratorDriver)CSharpGeneratorDriver
            .Create(new XmlToDescriptionGenerator())
            .RunGeneratorsAndUpdateCompilation(compilation, out var outputCompilation, out var diagnostics);

        var runResult = driver.GetRunResult();

        return new GeneratorRunResult
        {
            Success = !diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error),
            GeneratedSources = runResult.GeneratedTrees.Select(t => (t.FilePath, t.GetText())).ToList(),
            Diagnostics = diagnostics.ToList(),
            Compilation = outputCompilation
        };
    }

    private static void AssertGeneratedSourceEquals(
        [StringSyntax("C#-test")] string expected,
        [StringSyntax("C#-test")] string actual)
    {
        // Normalize line endings to \n, remove trailing whitespace from each line, and trim the end
        static string Normalize(string s)
        {
            var lines = s.Replace("\r\n", "\n").Replace("\r", "\n").Split('\n');
            for (int i = 0; i < lines.Length; i++)
            {
                lines[i] = lines[i].TrimEnd();
            }
            return string.Join('\n', lines).TrimEnd();
        }
        
        var normalizedExpected = Normalize(expected);
        var normalizedActual = Normalize(actual);
        
        Assert.Equal(normalizedExpected, normalizedActual);
    }

    private class GeneratorRunResult
    {
        public bool Success { get; set; }
        public List<(string FilePath, Microsoft.CodeAnalysis.Text.SourceText SourceText)> GeneratedSources { get; set; } = [];
        public List<Diagnostic> Diagnostics { get; set; } = [];
        public Compilation? Compilation { get; set; }
    }
}
